/*
	isnum XFCN, version 2
	15 Mar 1989 Greg Jorgensen, Mac DTS
	й Apple Computer Inc., 1989
	
	usage: isnum(expression)
	
	returns: true if expression is a valid number, false otherwise
	
	This version of isnum is more internationalized than the first.
	It uses the decimal point character from the ITL0 resource, and
	tries to handle multi-byte characters from non-Roman scripts.
	
	Expression must contain only digits (0-9). A leading + or - is allowed, and
	a single decimal point in any position is allowed. Scientific notation
	(1234.E+02) is not recognized.
	
*/

#include <MacTypes.h>
#include <ScriptMgr.h>
#include <IntlPkg.h>
#include <SetUpA4.h>
#include <strings.h>
#include <HyperXCmd.h>

#define		NIL		0L

/* Hypercard parameter block:

	typedef struct XCmdBlock {
		short	paramCount;     
	    Handle  params[16];
	    Handle  returnValue;      
	    Boolean	passFlag; 
	      
	    void	(*entryPoint)();
	    short	request;  
	    short	result;  
	    long	inArgs[8];
	    long	outArgs[4];
	   } XCmdBlock, *XCmdBlockPtr;
*/

/* еее */

pascal void main(paramPtr)
	XCmdBlockPtr	paramPtr;
{
	register	char	*s;			/* string ptr */
	register	char	c;			/* char holder */
	char				decPt;		/* decimal point char for this script */
	Boolean				valid;		/* true if a valid number	*/
	Boolean				aDigit;		/* to make sure we see at least one digit */
	int					d;			/* number of decimal points encountered */
	int					i;			/* character counter */
	Handle				srcH, dstH;	/* temp storage for Transliterate */
	Intl0Hndl			hItl;		/* for ITL 0 resource */
	
	/*** CODE STARTS HERE ***/
	
	RememberA0();					/* A0 points to this procedure */
	SetUpA4();						/* point A4 at this proc for literals */
	
	/*** Check parameters ***/
	
	if (paramPtr->paramCount != 1) {
		strcpy(*(paramPtr->returnValue), "argument error");
		return;
	}
	
	/*** initialize & set up return value ***/
	
	paramPtr->returnValue = NewHandle(6L);	/* set up return value */
	HLock(paramPtr->returnValue);
	HLock(paramPtr->params[0]);			/* lock param for de-reference */
	s = *(paramPtr->params[0]);			/* point to the string passed in */
	
	/*** Read ITL 0 resource to get decimal point character ***/
	
	hItl = (Intl0Hndl)IUGetIntl(0);
	if (hItl == NIL) {
		strcpy(*(paramPtr->returnValue), "can't read ITL0 rsrc");
		return;
	}
	decPt = (*hItl)->decimalPt;
	
	/*** Set up temp memory for Transliterate ***/
	
	srcH = NewHandle(2L);
	dstH = NewHandle(1L);
	if (srcH == NIL || dstH == NIL) {
		strcpy(*(paramPtr->returnValue), "can't allocate tmp memory");
		if (srcH != NIL)
			DisposHandle(srcH);
		if (dstH != NIL)
			DisposHandle(dstH);
		return;
	}
	
	/*** MAIN LOOP ***/
	
	/*** For every character:
			if it is a multi-byte character, try to convert it to Roman script
			if the character is a digit, or a leading + or -, or the only decimal point,
				this is a valid number, otherwise it isn't
	***/
	
	aDigit = FALSE;						/* set when we see a digit */
	valid = TRUE;						/* assume it is numeric */
	d = 0;								/* decimal points found */
	
	for (i=0; valid && ((c = *s) != '\0'); s++, i++) {
	
		/*** check for multi-byte chars (non-Roman scripts) ***/
		
		switch( CharByte(s,0) ) {
			case 0:							/* single-byte char */
				break;
			case -1:						/* multi-byte char */
				stccpy(*srcH, s, 2);
				s++;
				if (Transliterate(srcH, dstH, smTransAscii, (long)smMaskAll) )
					valid = FALSE;			/* translation error */
				else
					c = **dstH;				/* get the translated char */
				break;
			default:						/* unrecognized */
				valid = FALSE;
				break;
		}
		
		/*** now check the character ***/
		
		if (valid) {
			if (c >= '0' && c <= '9')
				aDigit = true;
			else if (c == '+' || c == '-')
				valid = (i == 0);
			else if (c == decPt)
				valid = ( ++d < 2);
			else
				valid = FALSE;
		}
	}
	
	/*** special cases ***/
	
		valid = valid && aDigit;			/* need at least one digit */
		if (i == 0) valid = TRUE;			/* null string considered numeric */
		
	/*** Return true or false ***/
	
	if (valid)
		strcpy(*(paramPtr->returnValue), "true");
	else
		strcpy(*(paramPtr->returnValue), "false");
	
	/*** Clean up ***/
	
	HUnlock(paramPtr->params[0]);
	HUnlock(paramPtr->returnValue);
	
	/* don't dispose of hItl here -- Intl Pkg owns it */
	
	DisposHandle(srcH);
	DisposHandle(dstH);
	RestoreA4();					/* point A4 back to where it was */
}

#include <XCmdGlue.inc.c>
